 //
//  NetworkTools.swift
//  测试-05-AFN Swift
//
//  Created by male on 15/10/15.
//  Copyright © 2015年 itheima. All rights reserved.
//

import UIKit
import AFNetworking

/// HTTP 请求方法枚举
enum HMRequestMethod: String {
    case GET = "GET"
    case POST = "POST"
}

// MARK: -网络工具
class NetworkTools: AFHTTPSessionManager {

    /// MARK: -引用程序信息
    
    private let appKey = "2761226266"
    private let appSecret = "96e9b0fdf8e14be27ded34446294cf88"
    private let redirectUrl = "http://www.baidu.com"
    
    /// 网络请求完成回调，类似于 OC 的 typeDefine
    typealias RWRequestCallBack = (result: AnyObject?, error: NSError?)->()

    
    // 单例
    static let sharedTools: NetworkTools = {
        
        let tools = NetworkTools(baseURL: nil)
        
        // 设置反序列化数据格式 - 系统会自动将 OC 框架中的 NSSet 转换成 Set
        tools.responseSerializer.acceptableContentTypes?.insert("text/plain")
        
        return tools
    }()
}
 
 /// MARK: - 发布微博
 extension NetworkTools {
 
    /// 发布微博
    /// see: (http://open.weibo.com/wiki/2/statuses/update)[http://open.weibo.com/wiki/2/statuses/update]
    /// see: (http://open.weibo.com/wiki/2/statuses/upload)[http://open.weibo.com/wiki/2/statuses/upload]
    func sendStatus(status: String, image: UIImage? ,finished: RWRequestCallBack) {
    
        
        // 获取 token 字典
        guard var params = UserAccountViewModel.sharedUserAccount.tokenDict else {
            
            finished(result: nil, error: NSError(domain: "cn.itcast.error", code: -1001, userInfo: ["message": "token 为空"]))
            
            return
        }
        
        // 设置参数
        params["status"] = status
        
        // 判断是否上传图片
        if image == nil {
        
            let urlString = "https://api.weibo.com/2/statuses/update.json"
            
            // 发起网络请求
            request(.POST, URLString: urlString, parameters: params, finished: finished)
        }else {
            let urlString = "https://upload.api.weibo.com/2/statuses/upload.json"
            
            let data = UIImagePNGRepresentation(image!)
            
            upload(urlString, data: data!, name: "pic", parameters: params, finished: finished)

            
            let url = NSString(data: data!, encoding: NSUTF8StringEncoding)
           
            print(url)
            
        }

    }
 }

/// MARK: - 微博数据相关的方法
extension NetworkTools {
    
    ///加载微博数据
    /// since_id 若指定此参数，则返回ID比since_id大的微博（即比since_id时间晚的微博），默认为0。
    /// max_id 若指定此参数，则返回ID小于或等于max_id的微博，默认为0。
    /// - see:[http://open.weibo.com/wiki/2/statuses/home_timeline](http://open.weibo.com/wiki/2/statuses/home_timeline)
    func loadStatus(since_id since_id: Int, max_id: Int, finished: RWRequestCallBack) {
    
        // 1. 获取 token 字典
        guard var params = UserAccountViewModel.sharedUserAccount.tokenDict else {
            
            finished(result: nil, error: NSError(domain: "cn.itcast.error", code: -1001, userInfo: ["message": "token 为空"]))
            
            return
        }
        
        // 判断是否下拉
        if since_id > 0 {
            params["since_id"] = since_id 
        }else if max_id > 0{
            params["max_id"] = max_id - 1
        }
        
        // 2. 准备网络参数
        let urlString = "https://api.weibo.com/2/statuses/home_timeline.json"
        
        // 3. 发起网络请求
        request(.GET, URLString: urlString, parameters: params, finished: finished)

    }

}

/// MARK: - 和用户相关的方法
extension NetworkTools {
    /// -see:[http://open.weibo.com/wiki/2/users/show](http://open.weibo.com/wiki/2/users/show)
    func loadUserInfo(uid: String, finished: RWRequestCallBack) {
        
        //获取 token 字典
        guard var params = UserAccountViewModel.sharedUserAccount.tokenDict else {
        
            finished(result: nil, error: NSError(domain: "cn.itcast.error", code: -1001, userInfo: ["message": "token 为空"]))
            
            return
        }
        
        let urlString = "https://api.weibo.com/2/users/show.json"
        params["uid"] = uid
        
        request(.GET, URLString: urlString, parameters: params, finished: finished)
    }
}

/// MARK: -OAuth 相关的方法
extension NetworkTools {
    
    /// OAuth 授权 URL
    ///作用： 直接可以打开链接
    ///- see: [http://open.weibo.com/wiki/Oauth2/authorize](http://open.weibo.com/wiki/Oauth2/authorize)
    var oauthURL: NSURL {
    
        let urlString = "https://api.weibo.com/oauth2/authorize?client_id=\(appKey)&redirect_uri=\(redirectUrl)"
        
        return NSURL(string: urlString)!
    }
    
    /// 加载AccessToken
    func loadAccessToken(code: String, finished:RWRequestCallBack){
    
        let urlString = "https://api.weibo.com/oauth2/access_token"
        
        let parames = ["client_id": appKey,
            "client_secret": appSecret,
            "grant_type": "authorization_code",
            "code": code,
            "redirect_uri": redirectUrl]
        
        request(.POST, URLString: urlString, parameters: parames, finished: finished)
        
//         //测试返回的数据内容 - AFN 默认的响应格式是 JSON，会直接反序列化
//         //如果要确认数据格式的问题
//         //如果是 NSNumber，则没有引号！在做 KVC 指定属性类型非常重要！
//                // 1> 设置相应数据格式是二进制的
//                responseSerializer = AFHTTPResponseSerializer()
//        
//                // 2> 发起网络请求
//                POST(urlString, parameters: parames, success: { (_, result) -> Void in
//        
//                    // 将二进制数据转换成字符串
//                    let json = NSString(data: result as! NSData, encoding: NSUTF8StringEncoding)
//        
//                    print(json)
//        
//                    // {"access_token":"2.00ml8IrF6dP8NEb33e7215aeRhrcdB",
//                    // "remind_in":"157679999",
//                    // "expires_in":157679999,
//                    // "uid":"5365823342"}
//                    
//                    }, failure: nil)

    }
}

// MARK: - 封装 AFN 网络方法
extension NetworkTools {
    
    /// 网络请求
    ///
    /// - parameter method:     GET / POST
    /// - parameter URLString:  URLString
    /// - parameter parameters: 参数字典
    /// - parameter finished:   完成回调
    private func request(method: HMRequestMethod, URLString: String, parameters: [String: AnyObject]?, finished: RWRequestCallBack) {
        
        // 定义成功回调
        let success = { (task: NSURLSessionDataTask, result: AnyObject) -> Void in
            finished(result: result, error: nil)
        }
        
        // 定义失败回调
        let failure = { (task: NSURLSessionDataTask, error: NSError) -> Void in
            // 在开发网络应用的时候，错误不要提示给用户，但是错误一定要输出！
            print(error)
            finished(result: nil, error: error)
        }
        
        if method == HMRequestMethod.GET {
            GET(URLString, parameters: parameters, success: success, failure: failure)
        } else {
            POST(URLString, parameters: parameters, success: success, failure: failure)
        }
        
    }
    
    /// 上传文件
    private func upload(URLString: String, data: NSData, name: String, var parameters: [String: AnyObject]?, finished: RWRequestCallBack) {
        
        // 设置 token 字典
        // 1. 设置 token 参数 －> 将 token 添加到 parameters 字典中
        // 判断 token 是否有效
        guard let token = UserAccountViewModel.sharedUserAccount.tokenDict else {
            // token 无效
            // 如果字典为 nil，通知调用方，token 无效
            finished(result: nil, error: NSError(domain: "cn.itcast.error", code: -1001, userInfo: ["message": "token 为空"]))
            
            return
        }
        
        // 设置 parameters 字典
        // 1> 判断参数字典是否有值
        if parameters == nil {
            parameters = [String: AnyObject]()
        }
        
        parameters!["access_token"] = token["access_token"]
        
        /**
        1. data 要上传文件的二进制数据
        2. name 是服务器定义的字段名称 － 后台接口文档会提示
        3. fileName 是保存在服务器的文件名，但是：现在通常可以`乱写`，后台会做后续的处理
        - 根据上传的文件，生成 缩略图，中等图，高清图
        - 保存在不同路径，并且自动生成文件名
        
        - fileName 是 HTTP 协议定义的属性
        4. mimeType / contentType: 客户端告诉服务器，二进制数据的准确类型
        - 大类型/小类型
        * image/jpg image/gif image/png
        * text/plain text/html
        * application/json
        - 无需记忆
        - 如果不想告诉服务器准确的类型
        * application/octet-stream
        */
        POST(URLString, parameters: parameters, constructingBodyWithBlock: { (formData) -> Void in
            
            formData.appendPartWithFileData(data, name: name, fileName: "xxx", mimeType: "application/octet-stream")
            
            }, success: { (_, result) -> Void in
                finished(result: result, error: nil)
            }) { (_, error) -> Void in
                print(error)
                finished(result: nil, error: error)
        }
    }
 }
